#!/usr/bin/env python
# This script is used to generate a static site.
import sys
import os
import re
from subprocess import getoutput
from datetime import datetime
from collections import OrderedDict
from glob import glob

print("Exec python:",sys.executable)
print("current_path:", os.getcwd())

ROOT = "/b"
WWW_PATH = os.getenv('HOME')+'/www'
PAGE_TPL = open("page.html").read()
errors = []
log = print


def basename(path):
    filename = os.path.split(path)[1]
    return os.path.splitext(filename)[0]


def getPostPath(path):
    return WWW_PATH + '/' + f"{ROOT[1:]}/{path[5:-3]}.html"


def getPostUrl(path):
    # return f'/p/{path[5:-3]}'
    return f"{ROOT}/{path[5:-3]}"


def updateAtom(blogs, max_items=40):
    from copy import copy
    from bs4 import BeautifulSoup as BS

    atomPath = f"./{ROOT[1:]}/atom.xml"
    if os.path.exists(atomPath):
        s = open(atomPath).read()
    else:
        s = f"""
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Ahuigo 的网络日志</title>
<link href="https://ahuigo.github.io{ROOT}/atom.xml" rel="self" type="application/atom+xml"/>
<updated>2018-08-17T13:46:49Z</updated>
<subtitle>ahuigo's Blog</subtitle>
<entry xml:base="https://ahuigo.github.io">
<title>vue instance</title>
<link href="/b/ria/vue-ins" rel="alternate" type="text/html"/>
<updated>2018-09-30T20:29:15Z</updated>
<summary/>
<published/>
<content/>
</entry></feed>
        """
    bs = BS(s, "lxml-xml")
    bs.updated.string = datetime.now().replace(microsecond=0).isoformat() + "Z"
    ori_entry = copy(bs.entry)
    ori_entry.content.string = ""

    # update
    for path, blog in blogs.items():
        href = getPostUrl(path)
        if bs.find("link", href=href):
            entry = bs.find("link", href=href).parent
        else:
            entry = copy(ori_entry)
            entry.link["href"] = href
            bs.entry.insert_before(entry)

        entry.title.string = blog["title"]
        entry.content.string = blog["content"][:100]
        entry.published.string = (
            datetime.strptime(blog["date"], "%Y-%m-%d")
            .replace(microsecond=0)
            .isoformat()
            + "Z"
        )
        entry.updated.string = (
            datetime.strptime(blog["updated"], "%Y-%m-%d")
            .replace(microsecond=0)
            .isoformat()
            + "Z"
        )

    # clear
    l = len(bs.feed.findChildren("entry"))
    if l > max_items:
        for i in bs.feed.findChildren("entry")[max_items:]:
            i.extract()

    open(atomPath, "wb").write(bs.encode())


def breakout(errors):
    log("\n".join(errors))
    quit(1)


current_date = datetime.now().strftime("%Y-%m-%d")


def parseBlog(path, withContent=False):
    blog = {"path": path}
    print(path)
    if withContent:
        data = open(path).read()
    else:
        data = open(path).read(200)
    if data.startswith("---\n"):
        pos = data.index("\n---\n", 4)
        blogStr = data[4:pos]
        data = data[pos + 5 :]
        for line in blogStr.split("\n"):
            k, v = line.split(":", 1)
            blog[k] = v.strip()
    if "title" not in blog:
        blog["title"] = data.split("\n", 1)[0][2:].strip()
    if not blog["title"]:
        quit(f"{path} has no title")
    if "date" not in blog:
        blog["date"] = current_date
    blog["content"] = data
    blog["updated"] = current_date
    return blog


def publishBlog(path, pager=""):
    import html
    import markdown2

    # post/a/t.md
    post_path = getPostPath(path)
    post_dir = os.path.dirname(post_path)
    if not os.path.exists(post_dir):
        os.mkdir(post_dir)
    if not path.startswith("post/p/"):
        log(f"Generate: {path} -> {post_path}")
    blog = parseBlog(path, True)
    meta = f"""---
title: {blog['title']}
date: {blog['date']}
updated: {blog['updated']}
---
"""
    md = f'{meta}{blog["content"]}'
    render_md = (
        re.sub(r"(?<=\n)\s+", "", PAGE_TPL)
        .replace("{ROOT}", ROOT)
        .replace("{MD_URL}", "%r" % path)
        .replace("{TITLE}", html.escape(blog["title"]))
        .replace(f'<pre id="pager"></pre>', f'<div id="pager">{pager}</div>')
    )
    if pager:
        render_md = render_md.replace(
            f'<pre id="markdown"></pre>',
            f'<div id="markdown2" v-pre>{markdown2.markdown(blog["content"])}</div>',
        )
    else:
        render_md = render_md.replace(
            f'<pre id="markdown"></pre>',
            f'<pre id="markdown" v-pre>{html.escape(md)}</pre>',
        )

    print("cwd:", os.getcwd())
    open(post_path, "w").write(render_md)


def genPager(page_urls, pos):
    pager = ""
    for i, page_url in enumerate(page_urls):
        pager += f' <a href="{page_url}">p{i}</a>' if i != pos else f" p{i}"
    return pager


def genIndexPages(index_blogs):
    files_num = len(index_blogs)
    SIZE = 40
    page_urls = []
    if not os.path.exists('post/p'):
        os.mkdir("post/p")
    page_files = []
    for i in range(0, files_num, SIZE):
        n = i // SIZE
        page_file = "post/index.md" if n == 0 else f"post/p/p{n}.md"
        page_files.append(page_file)
        page_urls.append(getPostUrl(page_file))

    from itertools import islice

    it_blogs = iter(index_blogs)
    for pos, page_file in enumerate(page_files):
        with open(page_file, "w") as fp:
            fp.write(f"# AHUIGO 的笔记\n")
            for path in islice(it_blogs, SIZE):
                blog = index_blogs[path]
                article = f'- {blog["date"]} [{blog["title"]}]({getPostUrl(path)}) '
                fp.write(article + "\n")
        publishBlog(page_file, genPager(page_urls, pos))
    getoutput(f"git add post/index.md")
    return page_files


def getIndexBlogs():
    index_blogs = OrderedDict()
    for index_path in ["post/index.md"] + sorted(
        glob("post/p/*.md"), key=lambda x: int(x[8:-3])
    ):
        for line in open(index_path):
            m = re.match(
                "^- (?P<created>\S+) \[(?P<title>[^\]]+)\]\((?P<path>/[^\)]+)\)", line
            )
            if m and m.group("path").startswith(f"{ROOT}/"):
                path = m.group("path").replace(f"{ROOT}/", "post/", 1) + ".md"
                index_blogs[path] = {
                    "title": m.group("title"),
                    "path": path,
                    "date": m.group("created"),
                }
    return index_blogs


if "all" in sys.argv:
    modified_linelist = []
    for path in glob("post/**/*.md", recursive=True):
        if not path.startswith("post/p/") and path != "post/index.md":
            modified_linelist.append(f"A\t{path}")
elif len(sys.argv) > 1:
    modified_linelist = [f"A\t{path}" for path in sys.argv[1:]]
else:
    cmd = 'git diff-index --cached --name-status --diff-filter=ACMRD HEAD -- post | grep -vE "\spost/(index|p/.+).md$" '
    modified_linelist = getoutput(cmd).strip().split("\n")
    modified_linelist = filter(lambda x: x, modified_linelist)

# breakout(modified_linelist)
if modified_linelist:
    # index_blogs = OrderedDict()
    index_blogs = getIndexBlogs()
    new_blogs = {}
    delete_files = []
    old_index_path_list = list(index_blogs.keys())
    for line in modified_linelist:
        status, path = line.split("\t")
        if status == "D":
            index_blogs.pop(path, None)
            delete_files.append(path)
            continue

        if not os.stat(path).st_size:
            continue

        blog = parseBlog(path)
        if "private" in blog:
            continue
        new_blogs[path] = blog
        index_blogs[path] = blog
        # 'priority' in blog:
        if path not in old_index_path_list:
            index_blogs.move_to_end(path, last=False)

    for path in delete_files:
        post_path = getPostPath(path)
        if os.path.exists(post_path):
            os.unlink(post_path)

    if new_blogs:
        from itertools import islice

        log("updateAtom, current_path:", os.getcwd())
        updateAtom({k: new_blogs[k] for k in islice(new_blogs, 10)})
        log("genIndexPages")
        genIndexPages(index_blogs)
        log("publishBlogs")
        for path in new_blogs.keys():
            publishBlog(path)

    if errors:
        breakout(errors)

if os.path.exists("no-commit"):
    log("no-commit")
    quit(1)
